<template>
  <el-dialog
    :visible.sync="visible"
    append-to-body
    class="dragCanvas_dialog"
    :title="title"
    :close-on-click-modal="false"
    :width="`${width}px`"
    v-dialogDrag="true"
    @close="handleClose"
  >
    <!-- <el-container class="mainDiv rowflex">
      <el-aside class="leftFiv" style="justify-content: start;width: 300px;padding: 0;margin-bottom: 0;">
        <div class="group-wrap">
          <div class="type-group">元素块</div>
          <div class="grid-item">
            <div
              class="element"
              v-for="(item, index) in elementList"
              draggable="true"
              :key="index"
              @dragstart="handleDragStart(index)"
            >
              <el-image
                :src="item.address"
                fit="fill"
              ></el-image>
            </div>
          </div>
        </div>
        <div class="group-wrap">
          <div class="type-group">图形</div>
          <div class="grid-item">
            <div
              draggable="true"
              class="element"
              v-for="(item, index) in graphicalList"
              :key="index"
              @dragstart="handleDaragGraphical(item.key)"
            >
              <div>{{ item.name }}</div>
            </div>
          </div>
        </div>
        <div class="group-wrap">
          <div class="type-group">文字</div>
          <div draggable="true" class="element" @dragstart="handleDaragText()">
            <svg-icon
              slot="prefix"
              icon-class="size"
              class="el-input__icon input-icon"
            />
            <div>文字</div>
          </div>
        </div>
      </el-aside>
      <div id="rightDiv" class="rightDiv">
        <canvas id="fabric"></canvas>
      </div>
      <div id="menu" class="menu-x" v-show="menuDisplay">
        <div class="menu-li" @click="sendToUp()">往上一层</div>
        <div class="menu-li" @click="sendToBack()">往下一层</div>
        <div class="menu-li" @click="sendToTop()">置于顶层</div>
        <div class="menu-li" @click="sendToBottom()">置于底层</div>
        <div class="menu-li" @click="copyElement()">复制</div>
        <div class="menu-li" @click="deleteElement()">删除</div>
      </div>
    </el-container> -->
    <iframe id="iframe"  width="100%" style="height: 87vh;" src="/exportModules" frameborder="1"></iframe>
    <div slot="footer">
      <el-button type="primary" @click="clear" size="small">清空</el-button>
      <el-button type="primary" @click="save" size="small">上传图片</el-button>
      <!-- <el-button type="primary" @click="zancun">暂存</el-button>
      <el-button type="primary" @click="refresh">恢复</el-button> -->
    </div>
  </el-dialog>
</template>

<script>
import { fabric } from "fabric";
import { upload } from "@/api/basicData/seal";
export default {
  data() {
    return {
      visible: false,
      title: '平面图',
      // 图标列表
      elementList: [
        {
          key: 1,
          address: require("@/assets/fabric/1.svg"),
        },
        {
          key: 2,
          address: require("@/assets/fabric/2.svg"),
        },
        {
          key: 3,
          address: require("@/assets/fabric/3.svg"),
        },
        {
          key: 4,
          address: require("@/assets/fabric/4.svg"),
        },
        {
          key: 5,
          address: require("@/assets/fabric/5.svg"),
        },
        {
          key: 6,
          address: require("@/assets/fabric/6.svg"),
        },
        {
          key: 7,
          address: require("@/assets/fabric/7.svg"),
        },
        {
          key: 8,
          address: require("@/assets/fabric/8.svg"),
        },
        {
          key: 9,
          address: require("@/assets/fabric/9.svg"),
        },
        {
          key: 10,
          address: require("@/assets/fabric/10.svg"),
        },
        {
          key: 11,
          address: require("@/assets/fabric/11.svg"),
        },
        {
          key: 12,
          address: require("@/assets/fabric/12.svg"),
        },
        {
          key: 13,
          address: require("@/assets/fabric/13.svg"),
        },
        {
          key: 14,
          address: require("@/assets/fabric/14.svg"),
        },
        {
          key: 15,
          address: require("@/assets/fabric/15.svg"),
        },
        {
          key: 16,
          address: require("@/assets/fabric/16.svg"),
        },
        {
          key: 17,
          address: require("@/assets/fabric/17.svg"),
        },
        {
          key: 18,
          address: require("@/assets/fabric/18.svg"),
        },
        {
          key: 19,
          address: require("@/assets/fabric/19.svg"),
        },
        {
          key: 20,
          address: require("@/assets/fabric/20.svg"),
        },
        {
          key: 21,
          address: require("@/assets/fabric/21.svg"),
        },
        {
          key: 22,
          address: require("@/assets/fabric/22.svg"),
        },
        {
          key: 23,
          address: require("@/assets/fabric/23.svg"),
        },
        {
          key: 24,
          address: require("@/assets/fabric/24.svg"),
        },
        {
          key: 25,
          address: require("@/assets/fabric/25.svg"),
        },
        {
          key: 26,
          address: require("@/assets/fabric/26.svg"),
        },
        {
          key: 27,
          address: require("@/assets/fabric/27.svg"),
        },
        {
          key: 28,
          address: require("@/assets/fabric/28.svg"),
        },
        {
          key: 29,
          address: require("@/assets/fabric/29.svg"),
        },
        {
          key: 30,
          address: require("@/assets/fabric/30.svg"),
        },
        {
          key: 31,
          address: require("@/assets/fabric/31.svg"),
        },
      ],
      // 图形列表
      graphicalList: [
        {
          key: "circle",
          name: "圆形",
        },
        {
          key: "triangle",
          name: "三角形",
        },
        {
          key: "rect",
          name: "矩形",
        },
        {
          key: "line",
          name: "直线",
        },
      ],
      // 画布背景图片
      canvasBackgroundImage: require("@/assets/login-bg.png"),
      // 画布
      canvas: null,
      //最后一次拖动的图片
      imageAddress: "",
      //是否拖动中
      isDragging: false,
      //最后的x轴方向的位置
      lastPosX: 0,
      //最后的y轴方向的位置
      lastPosY: 0,
      //菜单是否显示
      menuDisplay: false,
      //最后一次右键选中的元素
      lastMenu: null,
      option: {
        width: 500,
        height: 300
      },
      width: 1000,
      workspace: null
    };
  },
  mounted() {
    this.width = document.documentElement.clientWidth;
    window.addEventListener('message', (event) => {
      // 
      const { isDraw, dataUrl } = event.data
      if (isDraw) {
        console.log(dataUrl);
        
        var blob = this.dataURLtoBlob(dataUrl);
        console.log(blob);
        
        var file = this.blobToFile(blob, "截图.jpg");
        console.log(file);

        let fd = new FormData();
        fd.append("file", file);
        upload(fd).then((response) => {
          // console.log("uploadResponse", response);
          this.$modal.msgSuccess("上传成功");
          // this.clear();
          this.visible = false;
          this.$emit('confirm', response.data);
        });
      }
    }, true)
  },
  destroyed() {
    window.removeEventListener('resize', this.setZoomAuto)
  },
  methods: {
    openDialog() {
      this.visible = true
      this.$nextTick(() => {
        if (!this.canvas) {
          this.initCanvas();
        }
        this._initWorkspace()
        window.addEventListener('resize', this.setZoomAuto)
      })
    },
    //初始化画布
    initCanvas() {
      // 获取容器元素,得到父容器的宽和高
      const container = document.querySelector("#rightDiv");
      // 创建一个与容器宽高一致的 canvas 对象
      this.canvas = new fabric.Canvas("fabric", {
        width: container.offsetWidth,
        height: container.offsetHeight,
        fireRightClick: true, // 启用右键，button的数字为3
        stopContextMenu: true, // 禁止默认右键菜单
        controlsAboveOverlay: true, // 超出clipPath后仍然展示控制条
        // imageSmoothingEnabled: false, // 解决文字导出后不清晰问题
        preserveObjectStacking: true, // 当选择画布中的对象时，让对象不在顶层。
        backgroundColor: '#f0f0f0'
      });

      const width = container.offsetWidth * 0.9
      const height = container.offsetHeight * 0.9
      this.option = {
        width,
        height
      }

      // 设置画布的背景图片
      // this.setBackground(container.clientWidth, container.clientHeight);
      //监听元素是否被下放到画布上
      this.elementPlacement();
      //监听画布拖拽,包含三个监听事件
      this.canvasDragAndDrop();
      //监听画布缩放
      // this.canvasZoom();
    },
    //设置画布的背景图片
    setBackground(clientWidth, clientHeight) {
      fabric.Image.fromURL(this.canvasBackgroundImage, (img) => {
        // 缩放背景图片以适应画布
        // 如果背景图片宽度或高度大于画布宽度或高度
        if (img.width > clientWidth || img.height > clientHeight) {
          // 计算缩放比例
          let scaleX = clientWidth / img.width;
          let scaleY = clientHeight / img.height;
          let scale = Math.min(scaleX, scaleY);
          // 缩放背景图片
          img.scaleToWidth(img.width * scale);
          img.scaleToHeight(img.height * scale);
        } else {
          // 如果背景图片宽度和高度都小于或等于画布宽度和高度
          // 计算背景图片在画布中的位置
          img.left = (clientWidth - img.width) / 2;
          img.top = (clientHeight - img.height) / 2;
        }
        this.canvas.setBackgroundImage(img, this.canvas.renderAll.bind(this.canvas));
      });
    },
    setZoomAuto() {
      const container = document.getElementById("rightDiv");
      const width = container.offsetWidth;
      const height = container.offsetHeight;
      this.canvas.setWidth(width);
      this.canvas.setHeight(height);
      // console.dir(container);
    },
    //监听被拖动元素的图片
    handleDragStart(event) {
      this.imageAddress = this.elementList[event].address;
    },
    // 插入文字 text:文本
    handleDaragText(text) {
      this.imageAddress = null;
    },
    // 插入图形
    handleDaragGraphical(type) {
      this.imageAddress = type;
    },
    //监听元素是否被下放到画布上
    elementPlacement() {
      this.canvas.on("drop", (elt) => {
        // 画布元素距离浏览器左侧和顶部的距离
        let offset = {
          left: this.canvas.getSelectionElement().getBoundingClientRect().left,
          top: this.canvas.getSelectionElement().getBoundingClientRect().top,
        };
        // 鼠标坐标转换成画布的坐标（未经过缩放和平移的坐标）
        let point = {
          x: elt.e.x - offset.left,
          y: elt.e.y - offset.top,
        };
        // 转换后的坐标，restorePointerVpt 不受视窗变换的影响
        let pointerVpt = this.canvas.restorePointerVpt(point);
        //创建元素
        this.createElement(this.imageAddress, pointerVpt);
      });
    },
    //在画布上生成拖拽过来的元素
    createElement(imageAddress, pointerVpt) {
      let graphical = ["circle", "rect", "triangle", "line"];
      if (!imageAddress) {
        const textDOM = new fabric.Textbox("双击修改文字", {
          top: pointerVpt.y - 24, // 位置
          left: pointerVpt.x - 24,
          width: 120,
          fontSize: 17, // 文字大小
          textAlign: "center",
          fill: "#333", // 颜色
          level: 0, // 层级
          splitByGrapheme: true,
          editingBorderColor: "#666",
          borderColor: "#666",
          borderScaleFactor: 1, //border的宽度
        });
        this.canvas.add(textDOM); //添加文字
        this.canvas.bringToFront(textDOM); //优先级
      } else if (graphical.includes(imageAddress)) {
        switch (imageAddress) {
          case "rect":
            this.createRect(pointerVpt);
            break;
          case "circle":
            this.createCircle(pointerVpt);
            break;
          case "triangle":
            this.createTriangle(pointerVpt);
            break;
          case "line":
            this.createLine(pointerVpt);
            break;
        }
      } else {
        fabric.Image.fromURL(imageAddress, (oImg) => {
          //这个地方做了一下偏移，让鼠标位置为图标的中心，真实的位置信息要还原回去
          oImg.top = pointerVpt.y - 24;
          oImg.left = pointerVpt.x - 24;
          this.canvas.add(oImg);
        });
      }
    },
    // 创建rect
    createRect(pointerVpt) {
      const rect = new fabric.Rect({
        top: pointerVpt.y - 24,
        left: pointerVpt.x - 24,
        width: 100,
        height: 60,
        fill: "#fff",
        stroke: "#000",
      });
      this.canvas.add(rect);
    },
    // 创建circle
    createCircle(pointerVpt) {
      const circle = new fabric.Circle({
        top: pointerVpt.y - 24,
        left: pointerVpt.x - 24,
        radius: 30,
        fill: "#fff",
        stroke: "#000",
      });
      this.canvas.add(circle);
    },
    // 创建triangle
    createTriangle(pointerVpt) {
      const triangle = new fabric.Triangle({
        top: pointerVpt.y - 24,
        left: pointerVpt.x - 24,
        width: 100,
        height: 60,
        fill: "#fff",
        stroke: "#000",
      });
      this.canvas.add(triangle);
    },
    // 创建直线
    createLine(pointerVpt) {
      const line = new fabric.Line(
        [pointerVpt.x - 24, pointerVpt.y, pointerVpt.x + 164, pointerVpt.y],
        {
          fill: "#000",
          stroke: "#000",
          strokeWidth: 4,
        }
      );
      this.canvas.add(line);
    },
    //监听画布缩放
    canvasZoom() {
      this.canvas.on("mouse:wheel", (opt) => {
        const delta = opt.e.deltaY; // 滚轮，向上滚一下是 -100，向下滚一下是 100
        let zoom = this.canvas.getZoom(); // 获取画布当前缩放值
        zoom *= 0.999 ** delta;
        if (zoom > 20) zoom = 20; // 限制最大缩放级别
        if (zoom < 0.01) zoom = 0.01; // 限制最小缩放级别
        // 以鼠标所在位置为原点缩放
        this.canvas.zoomToPoint(
          {
            // 关键点
            x: opt.e.offsetX,
            y: opt.e.offsetY,
          },
          zoom // 传入修改后的缩放级别
        );
      });
    },
    // 监听画布拖拽，同时也监听了右键菜单
    canvasDragAndDrop() {
      // 按下鼠标事件
      this.canvas.on("mouse:down", (opt) => {
        var evt = opt.e;
        // 判断：右键，且在元素上右键
        // opt.button: 1-左键；2-中键；3-右键
        // 在画布上点击：opt.target 为 null
        if (opt.button === 3 && opt.target) {
          this.lastMenu = opt.target;
          // 框选多个不显示菜单
          if(this.lastMenu?._objects) 
            return false;
          let menu = document.getElementById("menu");
          // 禁止在菜单上的默认右键事件
          menu.oncontextmenu = function (e) {
            e.preventDefault();
          };
          // 显示菜单，设置右键菜单位置
          // 获取菜单组件的宽高
          //这个地方是左侧组件的宽度
          const leftWidth = "20%";
          const menuHeight = menu.childNodes.length * 40;
          // 当前鼠标位置
          let pointX = opt.pointer.x;
          let pointY = opt.pointer.y;
          // 计算菜单出现的位置
          // 如果鼠标靠近画布底部，菜单就出现在鼠标指针上方
          if (this.canvas.height - pointY <= menuHeight) {
            pointY -= menuHeight;
          }
          menu.style = `
                  visibility: visible;
                  left: calc(${pointX}px + ${leftWidth});
                  top: ${pointY}px;
                  z-index: 100;
                `;
          // 将菜单展示
          this.menuDisplay = true;
        } else {
          // 将菜单隐藏
          this.menuDisplay = false;
        }
        //拖拽
        if (evt.shiftKey === true) {
          this.isDragging = true;
          this.canvas.selection = false;
        }
      });
      // 移动鼠标事件
      this.canvas.on("mouse:move", (opt) => {
        if (this.isDragging && opt && opt.e) {
          var delta = new fabric.Point(opt.e.movementX, opt.e.movementY);
          this.canvas.relativePan(delta);
        }
      });
      // 松开鼠标事件
      this.canvas.on("mouse:up", (opt) => {
        this.isDragging = false;
        this.canvas.selection = true;
      });
    },
    //删除元素
    deleteElement() {
      // console.log(this.canvas);
      // this.canvas.getObjects()
      // this.canvas.setViewportTransform([1, 0, 0, 1, 50, 50]);
      // this.canvas.renderAll();
      // return
      this.canvas.remove(this.lastMenu);
      // 将菜单隐藏
      this.menuDisplay = false;
    },
    // 复制元素
    copyElement() {
      const that = this;
      this.lastMenu.clone(function (cloned) {
        that.canvas.add(cloned);
        cloned.top += 20;
        cloned.left += 20;
        that.canvas.setActiveObject(cloned);
      });
      this.menuDisplay = false;
    },
    // 往上一层
    sendToUp() {
      this.canvas.bringForward(this.lastMenu);
      // 将菜单隐藏
      this.menuDisplay = false;
    },
    // 往下一层
    sendToBack() {
      this.canvas.sendBackwards(this.lastMenu);
      // 将菜单隐藏
      this.menuDisplay = false;
    },
    // 置于顶层
    sendToTop() {
      this.canvas.bringToFront(this.lastMenu);
      this.menuDisplay = false;
    },
    // 置于底层
    sendToBottom() {
      this.canvas.sendToBack(this.lastMenu);
      this.menuDisplay = false;
    },
    // 初始化画布
    _initWorkspace() {
      const container = document.querySelector("#rightDiv");
      const { width, height } = this.option;
      const workspace = new fabric.Rect({
        fill: 'rgba(255,255,255,1)',
        width,
        height,
        id: 'workspace',
        strokeWidth: 0,
        left: (container.offsetWidth - width) / 2,
        top: (container.offsetHeight - height) / 2,
      });
      workspace.set('selectable', false);
      workspace.set('hasControls', false);
      workspace.set('evented', false);
      workspace.hoverCursor = 'default';
      this.workspace = workspace
      this.canvas.add(workspace);
      this.canvas.renderAll();
      this._initMask()

      if (this.canvas.clearHistory) {
        this.canvas.clearHistory();
      }
    },
    // 添加蒙层
    _initMask() {
      const container = document.querySelector("#rightDiv");
      // const center = this.canvas.getCenter();
      // const zoom = this.canvas.getZoom();
      // let zoomToPointNumber = zoom;
      // this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), zoomToPointNumber);

      const coverMask = new fabric.Rect({
        width: container.offsetWidth,
        height: container.offsetHeight,
        id: 'coverMask',
        fill: '#f0f0f0',
      });
      coverMask.set('selectable', false);
      coverMask.set('hasControls', false);
      coverMask.set('evented', false);
      coverMask.hoverCursor = 'default';
      this.workspace.clone(clone => {
        clone.left = -clone.width / 2;
        clone.top = -clone.height / 2;
        clone.inverted = true; 
        coverMask.clipPath = clone
        this.canvas.requestRenderAll();
      })
      this.canvas.add(coverMask);
      // canvas添加块时保持蒙层始终在最上层
      this.canvas.on('object:added', () => {
        coverMask.bringToFront();
      });
    },
    // 返回workspace对象
    getWorkspase() {
      return this.canvas.getObjects().find((item) => item.id === 'workspace');
    },
    // 获取实际渲染区域
    _getSaveOption() {
      const workspace = this.canvas
        .getObjects()
        .find((item) => item.id === 'workspace');
      console.log('getObjects', this.canvas.getObjects());
      const { left, top, width, height } = workspace;
      const option = {
        name: 'New Image',
        format: 'png',
        quality: 1,
        width,
        height,
        left,
        top,
      };
      return option;
    },
    // 图片保存
    save() {
      const options = this._getSaveOption()
      const url = this.canvas.toDataURL(options);
      console.log(url);
      
      var blob = this.dataURLtoBlob(url);
      var file = this.blobToFile(blob, "截图.jpg");
      console.log(file);

			let fd = new FormData();
			fd.append("file", file);
			upload(fd).then((response) => {
				// console.log("uploadResponse", response);
        this.$modal.msgSuccess("上传成功");
        this.clear();
        this.visible = false;
        this.$emit('confirm', response.data);
			});
      return
      
      // 组装a标签
      let elink = document.createElement("a");
      // 设置下载文件名
      elink.download = "截图.jpg";
      elink.style.display = "none";
      elink.href = URL.createObjectURL(blob);
      document.body.appendChild(elink);
      elink.click();
      document.body.removeChild(elink);
    },
    // 将base64转换为blob
    dataURLtoBlob: function (dataurl) {
      var arr = dataurl.split(",");
      var mime = arr[0].match(/:(.*?);/)[1];
      var bstr = atob(arr[1]);
      var n = bstr.length;
      var u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], { type: mime });
    },
    // 将blob转换为file
    blobToFile: function (theBlob, fileName) {
      theBlob.lastModifiedDate = new Date();
      theBlob.name = fileName;
      return theBlob;
    },
    // 清空画布 // 清空除coverMask和workspace的对象
    clear() {
      for (let index = 0; index < this.canvas.getObjects().length; index++) {
        const obj = this.canvas.getObjects()[index];
        if (obj.id === 'workspace' || obj.id === 'workspace') continue;
        this.canvas.remove(obj);
      }
      this.canvas.discardActiveObject();
      this.canvas.renderAll();
      // this.canvas.clear();
    },
    // 暂存
    zancun() {
      const canvasJson = this.canvas.toJSON();
      console.log(canvasJson)
    },
    // 恢复
    refresh() {
      this.canvas.loadFromJSON({}, () => {
        this.canvas.renderAll();
        this.stateIndex = index;
      });
    },
    handleClose() {
      this.clear()
    }
  },
};
</script>

<style lang="scss" scoped>
.dragCanvas_dialog {
  ::v-deep .el-dialog {
		max-height: 100%;
		height: 100%;
		.el-dialog__body {
			padding: 0;
		}
	}
}
// flex横向布局
.rowflex {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}

.group-wrap {
  border-bottom: 1px solid #eee;
}

.type-group {
  font-weight: bold;
  margin-left: 5px;
  margin-top: 10px;
  margin-bottom: 20px;
}

.grid-item {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px; /* 格子间隔 */
}

// flex纵向布局
.columnflex {
  display: flex;
  align-items: center;
  justify-content: center;
}

// 主div
.mainDiv {
  height: calc(100vh - 118px) !important;
  width: 100%;
  min-width: 1000px;
  padding: 0 10px;
}

/* 左侧元素区 */
.leftFiv {
  height: 100%;
  width: 20%;
  padding: 10px;
  // 元素块
  .element {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    width: 50px;
    height: 50px;
    min-width: 50px;
    margin-bottom: 20px;
    border: 1px solid #eee;
    cursor: move;
    &:hover {
      box-shadow: 0 0 2px 2px #999;
      transition: all 0.4s;
    }

    .element_item {
      height: 90%;
      width: 90%;
    }
  }
}

/* 右侧画布区 */
.rightDiv {
  flex: 1;
  height: 100%;
  border: 1px solid #999;
}

.menu-x {
  z-index: -100;
  position: absolute;
  top: 0;
  left: 0;
  box-sizing: border-box;
  border-radius: 4px;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
  background-color: #fff;
}

/* 菜单每个选项 */
.menu-li {
  box-sizing: border-box;
  padding: 4px 8px;
  border-bottom: 1px solid #ccc;
  cursor: pointer;
  line-height: 30px;
  height: 40px;
  width: 120px;
}

/* 鼠标经过的选项，更改背景色 */
.menu-li:hover {
  background-color: antiquewhite;
}

/* 第一个选项，顶部两角是圆角 */
.menu-li:first-child {
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
}

/* 最后一个选项，底部两角是圆角，底部不需要边框 */
.menu-li:last-child {
  border-bottom: none;
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
}
</style>
